/**
 * \file webrequest.h
 *       Filename:  webrequest.h
 * =====================================================================================
 * 
 * 
 *    Description:  Definition of methods for HTTP web access. Since the algorithms are
 *    				able to import compressed data, an uncompression library is needed.
 *    				In this module, we use standard LibZ.
 * 
 *        Version:  1.0
 *        Created:  13/11/2009 00:07:44
 *       Revision:  none
 *       Compiler:  gcc
 * 
 *         Author:  François Hissel (fh), francois.hissel@m4x.org
 *        Company:  
 * 
 * =====================================================================================
 */

#ifndef  WEBREQUEST_H_INC
#define  WEBREQUEST_H_INC

#include	<netdb.h>

//#define OSM_PREFIX "http://"
//#define OSM_HOST "www.setra.equipement.gouv.fr"
//#define OSM_EXPORT "/"
#define	HTTP_PORT	"80"			//!< Standard port of an HTTP server 
#define STRING_SIZE 0xff	//!< Size of buffers for string manipulations. In particular this constant is used to define the size of the buffer for the storing of the website address
#define	BUFFER_SIZE	0x10000			//!< Size of buffer for loading the headers of a HTTP server response. The user must make sure this value is greater than the real size of the headers, or the downloading function won't work.
#define PATH_SIZE 250	//!< Maximum size of paths on the remote server
#define	TIMEOUT 20			//!< Timeout for HTTP requests, measured in seconds

extern char proxy[STRING_SIZE];	//!< Name of proxy server 
extern char proxy_port[STRING_SIZE];	//!< Port of proxy server
extern const char* http_prefix;	//!< Prefix of an HTTP request
extern const char* http_headers;	//!< Headers for an HTTP request
extern const char* http_post_form;	//!< Headers for a POST request

/**
 * \struct Cookie
 * \brief Definition of a cookie as used in HTML web pages
 *
 * This structure defines a cookie type, as used to personalize HTML web pages
 */
typedef struct Cookie {
	char *name;	//!< Name of the cookie
	char *value;	//!< Value of the cookie
} Cookie;

/**
 * \struct Cookies
 * \brief Chained list of cookies
 *
 * This structure stores a chained list of cookies.
 */
typedef struct Cookies {
	Cookie cookie;	//!< Cookie in the current node
	struct Cookies *next;	//!< End of the list
} Cookies;

/**
 * \brief Looks for a particular cookie in the cookies list by its name
 *
 * This function goes through the cookies list and looks for a cookie with the name given as argument. It is case-sensitive. The function returns a pointer to the cookie node if it is found, and 0 otherwise
 * \param cl Cookies list
 * \param name Name of the cookie to search
 * \return Pointer to the cookie node if it is found (access it with pointer.cookie), or 0 otherwise
 */
Cookies *get_cookie(Cookies *cl,char *name);

/**
 * \brief Prints all the cookies in a string, in a format which can be sent to a webserver
 *
 * This function prints all the cookies of the list in a string, which can be used in a request header to a HTTP server. No ending #0 is added. The buffer should be already allocated before the call to the function and have a size large enough to contain the whole string. The function returns the total length of the string.
 * \param c Pointer to the list of cookies
 * \param buffer String where the list of cookies will be printed.
 * \return Length of the string
 */
size_t print_cookies(Cookies *c,char *buffer);

/**
 * \brief Free the memory associated with a cookies list and destroy all the contained cookies
 *
 * This function releases all the memory associated with a cookies list, including the cookies inside the list.
 * \param c Pointer to the list of cookies
 */
void free_cookies(Cookies *c);

/**
 * \brief Look for a substring in a buffer
 *
 * This function looks for the indicated substring in the buffer starting at position buffer and of a length of num bytes. If the substring is not found, the function returns 0. Otherwise, it returns the starting position of the substring in the buffer.
 * \param buffer String in which the search will take place
 * \param num Number of bytes of the buffer, the search will not go beyond this limit
 * \param substring Substring to search in the buffer
 * \param case_sensitive If set to 0, search is not case-sensitive, that is two strings will be considered equal even if some characters do not have the same case. Otherwise, search is case-sensitive.
 * \return Pointer to the starting position of the substring in the buffer, 0 if the substring is not found
 */
char* strnstr(char *buffer,size_t num,char *substring,int case_sensitive); 

/**
 * \brief Resolve web address
 *
 * This function connects to a name server to resolve the host name given as argument.
 * \param hostname Name of the host
 * \param port Port of the host on which to connect
 * \param address Reference to an address structure which can be used by a socket operation
 * \return 0 if function was successful, a non-zero value otherwise
 */
int resolve(const char *hostname,const char *port,struct addrinfo **address);

/**
 * \brief Upload a file on the web server
 *
 * This function tries to upload a file on the web server at the address in hostinfo, using a POST request with a multipart content. It calculates the standard path using the proxy configuration, adds it at the beginning of the header, in the Host field, and fills in the User-Agent, Accept, Accept-Encoding, and Accept-Charset fields. A file pointer is given as argument: the file must be accessible from the current user. The length of the body is calculated and added in the headers. But the socket is immediatly closed and the program does not try to read the response.
 * \param hostinfo Structure containing information about the remote host (address, name, port...)
 * \param host Real host name
 * \param path Path of the file on the server, which may include all necessary parameters
 * \param filename Name of the new remote file
 * \param file Pointer to the file
 * \param filesize Length of the file in bytes, it should be the exact size of the previous file
 * \param cl Pointer to a list of cookies. If this variable is not NULL and the server sets a new cookie, it will be stored in this variable. See also function request for more information on this variable
 * \return 0 if everything went fine, a non-zero value otherwise
 */
int upload_request(struct addrinfo *hostinfo,const char *host,const char *path,const char *filename,FILE *file,ssize_t filesize,Cookies *cl);

/**
 * \brief Send a custom request to the web server
 *
 * This function connects to the desired website, using an HTTP protocol. It then sends a custom request, built with the different parameters. The request may be a GET or a POST one according to the value of body. It checks the global variable proxy to find if a proxy should be used and changes the headers according to its value. This function does not try to read the response of the server. It returns 0 if everything went fine, and -1 if an error occured. A message may then be printed on stderr.
 * \param socket_fd The function opens a new socket but does not close it so that the caller can read the response. At the end of the function, this variable holds the descriptor of the socket. If the pointer is null, the socket is closed at the end of the function.
 * \param hostinfo Structure containing information about the remote host (address, name, port...)
 * \param host Real host name
 * \param path Path of the file on the server, which may include all necessary parameters
 * \param headers Headers of the request, some of which are automatically generated and must not be included in this variable: host, user-agent, cookie, content-length
 * \param body Body of the request, only used for POST requests. For GET requests, this variable should be NULL
 * \param cl Pointer to a list of cookies. If this variable is not NULL and the server sets a new cookie, it will be stored in this variable. See also function request for more information on this variable
 */
int send_custom(int *socket_fd,struct addrinfo *hostinfo,const char *host,const char *path,const char *headers,const char *body,Cookies *cl);

/**
 * \brief Downloads a file from the website which address is given in argument
 *
 * This function connects to the desired website, using an HTTP protocol, and downloads the file given in argument, saving it on disk. The request may be a GET or a POST one according to the value of body. It checks the global variable proxy to find if a proxy should be used and changes the headers according to its value. The website must reference a file, all headers generated by web server or intermediate proxy will be discarded. Zlib and Gzip-compressed files (gzip, deflate) are supported and will be automatically extracted before being saved on the disk. The function returns the size of the downloaded file. If an error occurs during the reading, the function returns -1 and a message is printed on stderr.
 * \param fd Descriptor of the file on which the content of the website will be saved, the file must already be opened. If this descriptor is null, the request will be sent but the socket will immediatly be closed and the program will not try to read the response
 * \param hostinfo Structure containing information about the remote host (address, name, port...)
 * \param host Real host name
 * \param path Path of the file on the server, which may include all necessary parameters
 * \param body Body of the request, only used for POST requests. For GET requests, this variable should be NULL
 * \param cl Pointer to a list of cookies. If this variable is not NULL and the server sets a new cookie, it will be stored in this variable. See also function request for more information on this variable
 * \return Number of bytes of the newly-created file, which is the number of bytes downloaded from the web site (excluding the headers) if the file is not zipped, or the size of the extracted file otherwise. If an HTTP header is detected, the HTTP return code should be written in the first line of the header. It is parsed, and if not equal to 200 (OK), the opposite of the return code is returned before the function tries to read the body of the response.
 */
long request_addr(FILE* fd,struct addrinfo *hostinfo,const char *host,const char *path,const char *body,Cookies **cl);

/**
 * \brief Downloads a file from the website which address is given in argument
 *
 * This function connects to the desired website, using an HTTP protocol, and downloads the file given in argument, saving it on disk. It does only call the latter one with the same name, after having resolved the host name. It may use a proxy if one was configured previously.
 * \param fd Descriptor of the file on which the content of the website will be saved, the file must already be opened. If this descriptor is null, the request will be sent but the socket will immediatly be closed and the program will not try to read the response
 * \param host Host name of the web server
 * \param port Port to use for the connection : the port must be open and accept TCP connections with HTTP protocols
 * \param path Path of the file on the server, which may include all necessary parameters
 * \param body Body of the request, only used for POST requests. For GET requests, this variable should be NULL
 * \param cl Pointer to a list of cookies. If this variable is not NULL and the server sets a new cookie, it will be stored in this variable. Since the current value of the pointer is used as the queue of the list, the new elements being inserted at the beginning of it, the initial value of the list should be set to 0. Moreover, the cookies already stored in the list are sent to the server with the request, no matter which domain set them (remember this is only a lightweight function and in mostly intended for scripts connecting to one remote host only)
 * \return Number of bytes of the newly-created file, which is the number of bytes downloaded from the web site (excluding the headers) if the file is not zipped, or the size of the extracted file otherwise. 
 */
long request(FILE* fd,const char *host,const char *port,const char *path,const char *body,Cookies **cl);

#endif   // ----- #ifndef WEBREQUEST_H_INC  -----
